import cn.tedu.redis.demo.RedisApplication;
import com.alibaba.fastjson2.JSON;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.GeoOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.domain.geo.GeoLocation;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.util.List;

@SpringBootTest(classes = RedisApplication.class)
public class RedisTestApplication {
    @Autowired
    private RedisTemplate redisTemplate;
    @Test
    public void stringSerializer() {
        // 1.从客户端拿到底层连接对象,手动指定序列化方式
        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        // 2.connection所有api 除了需要手动指定序列化,api和命令完全一样
        connection.set("name".getBytes(),"张三".getBytes());
        // 3.读取
        byte[] bytes = connection.get("name".getBytes());
        System.out.println(new String(bytes));
    }
    @Test
    public void jsonSerializer() {
        CacheKey cacheKey = new CacheKey("user","1");
        UserCachePO userCachePO = new UserCachePO(18,"张三");
        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        String cacheKeyStr = JSON.toJSONString(cacheKey);
        String userStr = JSON.toJSONString(userCachePO);
        connection.set(cacheKeyStr.getBytes(),userStr.getBytes());
        byte[] bytes = connection.get(cacheKeyStr.getBytes());
        UserCachePO value = JSON.parseObject(new String(bytes), UserCachePO.class);
        System.out.println(value);
        connection.del(cacheKeyStr.getBytes());
    }
    @Test
    public void stringRedisSerializer() {
        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        connection.set(RedisSerializer.string().serialize("name"), RedisSerializer.string().serialize("张三"));
        byte[] bytes = connection.get(RedisSerializer.string().serialize("name"));
        System.out.println(RedisSerializer.string().deserialize(bytes));
    }
    @Test
    public void jsonRedisSerializer() {
        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        CacheKey cacheKey = new CacheKey("user","1");
        UserCachePO userCachePO = new UserCachePO(18,"张三");
        connection.set(RedisSerializer.json().serialize(cacheKey), RedisSerializer.json().serialize(userCachePO));
        byte[] bytes = connection.get(RedisSerializer.json().serialize(cacheKey));
        System.out.println(RedisSerializer.json().deserialize(bytes));
        connection.del(RedisSerializer.json().serialize(cacheKey));
    }
    @Test
    public void test01(){
        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        connection.set("gender".getBytes(),"male".getBytes());
        Boolean result = connection.exists(RedisSerializer.string().serialize("gender"));
        System.out.println(result);//true
        connection.del("gender".getBytes());
    }
    @Test
    public void test02(){
        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        //1.set key value
        String key="user";
        UserCachePO userCachePO=new UserCachePO(18,"张三");
        connection.set(key.getBytes(), RedisSerializer.java().serialize(userCachePO));
        //2.exists key
        Boolean result = connection.exists(RedisSerializer.string().serialize(key));
        System.out.println(result);
        //3.get key
        byte[] bytes = connection.get(RedisSerializer.string().serialize(key));
        System.out.println( RedisSerializer.java().deserialize(bytes));
        connection.del(RedisSerializer.string().serialize(key));
    }
    @Test
    public void test03(){
        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        String key="num";
        Integer value=105;
        connection.set(key.getBytes(),RedisSerializer.string().serialize(value+""));
        Long result = connection.incr(key.getBytes());
        System.out.println(result);
    }
    @Test
    public void geoAdd(){
        //1. geoadd beijing_stations 116 39 userCachePO redisTemplate拿到操作GEO 子对象
        /**
         * 这个命令的key值 做序列化可以用哪种方式 string|json|java
         * 这个命令的value值 string|json|java
         */
        GeoOperations geoOperations = redisTemplate.opsForGeo();
        Point point1=new Point(116,39);
        UserCachePO po1= new UserCachePO(18,"张三");
        Point point2=new Point(117,40);
        UserCachePO po2= new UserCachePO(19,"李四");
        Point point3=new Point(118,41);
        UserCachePO po3= new UserCachePO(20,"王五");
        String key="beijing_stations";
        geoOperations.add(key,point1,po1);
        geoOperations.add(key,point2,po2);
        geoOperations.add(key,point3,po3);
    }
    @Test
    public void geoDist(){
        GeoOperations geoOperations = redisTemplate.opsForGeo();
        // 1.geodist beijing_stations po1 po2 m|km|ft|mi
        UserCachePO po1= new UserCachePO(18,"张三");
        UserCachePO po2= new UserCachePO(19,"李四");
        String  key="beijing_stations";
        Distance distance1 = geoOperations.distance(key, po1, po2);
        // 2.解析返回值  Distance 有2个属性 value距离数值 unit距离单位 默认是m
        System.out.println(distance1.getValue());
        System.out.println(distance1.getUnit());
        // 3.填写距离单位
        Distance distance2 = geoOperations.distance(key, po1, po2, RedisGeoCommands.DistanceUnit.KILOMETERS);
        System.out.println(distance2.getValue());
        System.out.println(distance2.getUnit());
    }
    // georadius 客户端封装最复杂的 手动转化类型
    @Test
    public void geoRadius(){
        GeoOperations geoOperations = redisTemplate.opsForGeo();
        // 1.georadius beijing_stations 115 36 1000 km
        /**
         * 这个命令提供的参数包括
         * key值
         * point中心点
         * distance半径距离 单位 命令选项 km|m|mi|ft一致的
         */
        String key="beijing_stations";
        // 创建查询范围circle
        Circle circle=new Circle(115,38,1000000);
        GeoResults geoResults = geoOperations.radius(key, circle);
        // 2.把所有查询条件,要求都已经准备好 查询结果需要解析
        // 2.1拿到命中的对象 集合results
        List contents = geoResults.getContent();
        // 2.2循环 转化类型
        for (Object content : contents) {
            // 转化 GeoResult
            if (content instanceof GeoResult){
                GeoResult geoResult = (GeoResult) content;
                // 拿到content和distance
                Object item = geoResult.getContent();
                if (item instanceof RedisGeoCommands.GeoLocation){
                    // name point
                    RedisGeoCommands.GeoLocation locationItem = (RedisGeoCommands.GeoLocation) item;
                    Object value = locationItem.getName();
                    if (value instanceof UserCachePO){
                        System.out.println(value);
                    }
                    locationItem.getPoint();//目前是空的
                }
            }
        }
    }
    @Test
    public void geoRadiusT() {
        GeoOperations operations = redisTemplate.opsForGeo();
        String key="beijing_stations";
        Circle circle=new Circle(115,38,1000000);
        GeoResults<GeoLocation<UserCachePO>> geoResults = operations.radius(key, circle);
        List<GeoResult<GeoLocation<UserCachePO>>> contents = geoResults.getContent();
        contents.forEach(content -> {
            GeoLocation<UserCachePO> item = content.getContent();
            UserCachePO po = item.getName();
            System.out.println(po);
        });
    }
    //georadius添加选项
    @Test
    public void geoRadiusWithArgs(){
        GeoOperations operations = redisTemplate.opsForGeo();
        String key="beijing_stations";
        Circle circle=new Circle(115,38,1000000);
        // georadius beijing_stations 115 38 1000000 withcoord withdist
        RedisGeoCommands.GeoRadiusCommandArgs args =
        RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
        .includeDistance()// withdist
        .includeCoordinates();// withcoord
        GeoResults<GeoLocation<UserCachePO>> geoResults = operations.radius(key, circle, args);
        List<GeoResult<GeoLocation<UserCachePO>>> contents = geoResults.getContent();
        // 2.把所有查询条件,要求都已经准备好 查询结果需要解析
        // 2.1拿到命中的对象 集合results
        contents.forEach(content -> {
            GeoLocation<UserCachePO> item = content.getContent();
            Distance distance = content.getDistance();
            System.out.println(distance);
            UserCachePO po = item.getName();
            Point point = item.getPoint();
            System.out.println(point);
            System.out.println(po);
        });
    }
}
